package net.keebook.webapp.bean;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.TimeZone;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.inject.Inject;

import net.keebook.webapp.dao.PasswordResetRequestDao;
import net.keebook.webapp.dao.SettingDao;
import net.keebook.webapp.dao.UserDao;
import net.keebook.webapp.entity.PasswordResetRequest;
import net.keebook.webapp.entity.User;
import net.keebook.webapp.util.BCrypt;
import net.keebook.webapp.util.DateUtil;
import net.keebook.webapp.util.Mail;
import net.keebook.webapp.util.MessageBundle;
import net.keebook.webapp.util.Messages;
import net.keebook.webapp.util.SettingId;

@ManagedBean
@RequestScoped
public class ResetPasswordBean {
	private String username;
	private Boolean passwordChecked;
	private String password;
	private PasswordResetRequest resetRequest;
	@Inject
	private SettingDao settingDao;
	@Inject
	private UserDao userDao;
	@Inject
	private PasswordResetRequestDao passwordResetRequestDao;
	
	@PostConstruct
	public void init() {
		String id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
		if (id != null && !id.isEmpty()) {
			PasswordResetRequest resetRequest = getPasswordResetRequestDao().get(id);
			setResetRequest(resetRequest);
		}
	}
	
	private User lookupUser(String username) {
		User user = getUserDao().getPasswordUserByEmail(username);
		if (user == null) {
			user = getUserDao().getPasswordUserByUsername(username);
		}
		return user;
	}
	
	public void apply() throws IOException {
		User user = lookupUser(getUsername());
		PasswordResetRequest resetRequest = new PasswordResetRequest();
		resetRequest.setCreationDate(DateUtil.getUtcTimestamp(TimeZone.getTimeZone(getSettingDao().get(SettingId.SYSTEM_TIMEZONE).getValue())));
		resetRequest.setUser(user);
		getPasswordResetRequestDao().store(resetRequest);
		
		String url = getSettingDao().get(SettingId.PUBLIC_URL).getValue() + "/services/resetpassword/" + resetRequest.getExposableId();
		String message = MessageBundle.get().getString("mail.resetPasswordMail");
		message = MessageFormat.format(message, url);
		
		Mail mail = new Mail(
				getSettingDao().get(SettingId.SMTP_HOST).getValue(), 
				getSettingDao().get(SettingId.SMTP_PORT).getLong().intValue(),
				getSettingDao().get(SettingId.SMTP_AUTH).getBoolean(),
				getSettingDao().get(SettingId.SMTP_USERNAME).getValue(),
				getSettingDao().get(SettingId.SMTP_PASSWORD).getValue(),
				getSettingDao().get(SettingId.SMTP_ENABLE).getBoolean());
		try {
			mail.sendMail(
				getSettingDao().get(SettingId.SMTP_SENDER_ADDRESS).getValue(),
				"KeeBook",
				user.getEmail(),
				null,
				MessageBundle.get().getString("mail.resetPasswordMailSubject"),
				message);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		FacesContext.getCurrentInstance().getExternalContext().redirect("login.xhtml?msg="+Messages.PASSWORD_RESET_MAIL_SENT);
	}
	
	public void changePassword() throws IOException {
		PasswordResetRequest resetRequest = getResetRequest();
		User user = resetRequest.getUser();
		user.setHashedPassword(BCrypt.hashpw(getPassword(), BCrypt.gensalt()));
		getUserDao().update(user);
		
		getPasswordResetRequestDao().delete(resetRequest);
		
		FacesContext.getCurrentInstance().getExternalContext().redirect("login.xhtml?msg="+Messages.PASSWORD_RESET);
	}
	
	public void validateUsername(FacesContext context, UIComponent component, Object value) {
		String username = (String)value;
		User user = lookupUser(username);
		if (user == null) {
			((UIInput)component).setValid(false);
			context.addMessage(component.getClientId(context), new FacesMessage(MessageBundle.get().getString("error.noSuchUser")));
			return;
		}
		if (!user.getEnabled()) {
			((UIInput)component).setValid(false);
			context.addMessage(component.getClientId(context), new FacesMessage(MessageBundle.get().getString("error.accountDisabled")));
			return;
		}
		if (!user.getConfirmed()) {
			((UIInput)component).setValid(false);
			context.addMessage(component.getClientId(context), new FacesMessage(MessageBundle.get().getString("error.emailNotConfirmed")));
			return;
		}
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public SettingDao getSettingDao() {
		return settingDao;
	}

	public void setSettingDao(SettingDao settingDao) {
		this.settingDao = settingDao;
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	public PasswordResetRequestDao getPasswordResetRequestDao() {
		return passwordResetRequestDao;
	}

	public void setPasswordResetRequestDao(PasswordResetRequestDao passwordResetRequestDao) {
		this.passwordResetRequestDao = passwordResetRequestDao;
	}

	public Boolean getPasswordChecked() {
		return passwordChecked;
	}

	public void setPasswordChecked(Boolean passwordChecked) {
		this.passwordChecked = passwordChecked;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public PasswordResetRequest getResetRequest() {
		return resetRequest;
	}

	public void setResetRequest(PasswordResetRequest resetRequest) {
		this.resetRequest = resetRequest;
	}
}
